package gr.atc.epart;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;


public class HttpConnector
{
	private int CONNECTION_TIMEOUT = 15000;
	private int WAIT_RESPONSE_TIEMOUT = 15000;
	

	private Handler _callerResponseHandler;
	private int		_requestId;
	private DefaultHttpClient _client;
		
	private final ResponseHandler<String> _httpResponseHandler = new ResponseHandler<String>()
	{
		public String handleResponse(HttpResponse response)
		{
			
			String result = extractHttpResponse(response);
				
			Message message = new Message();
			message.what = _requestId;
			
			Bundle bundle = new Bundle();
			bundle.putString("RESPONSE", result);
			bundle.putSerializable("HEADERS", response.getAllHeaders());
			
			message.setData(bundle);
			_callerResponseHandler.sendMessage(message);

			return result;
		}
	};
	
	
	public HttpConnector()
	{

		HttpParams httpParameters = new BasicHttpParams();
		// set the maximum time-out for connecting to the server
		HttpConnectionParams.setConnectionTimeout(httpParameters,CONNECTION_TIMEOUT);
		HttpConnectionParams.setSoTimeout(httpParameters, WAIT_RESPONSE_TIEMOUT);
		HttpConnectionParams.setTcpNoDelay(httpParameters, true);
		
		_client = new DefaultHttpClient(httpParameters);
		
		
		if (EPartSettings.getInstance().isProxyServerRequired() && 
			EPartSettings.getInstance().getProxyServer() != null)
			_client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, EPartSettings.getInstance().getProxyServer());
		


	}
	
	
	//
	// Asynchronous version of HTTP Put
	//
	public void executePutRequestAsync(final String url,int requestId, FileEntity filetoUpload,Handler responseHandler)
	{
		executePutRequestAsync(url, requestId, filetoUpload,responseHandler,null);
	}

	public void executePutRequestAsync(final String url,int requestId, final FileEntity filetoUpload,Handler responseHandler,final Header[] headers)
	{
		this._callerResponseHandler = responseHandler;
		this._requestId = requestId;
		 new Thread() 
		 { 
				@Override
				public void run() 
				{
					try
					{
						HttpPut httpMethod = new HttpPut(url);
						
						if (headers != null)
							httpMethod.setHeaders(headers);

						httpMethod.setEntity(filetoUpload);
						
						_client.execute(httpMethod, _httpResponseHandler);
					}
					catch (ClientProtocolException e)
					{

					} catch (IOException e)
					{
					}
				}
		 }.start();
	
	}
	
	
	//
	// Asynchronous version of HTTP Get
	//
	
	public void executeGetRequestAsync(final String url,int requestId, Handler responseHandler)
	{
		executeGetRequestAsync(url, requestId, responseHandler,null);
	}

	public void executeGetRequestAsync(final String url,int requestId, Handler responseHandler,final Header[] headers)
	{
		this._callerResponseHandler = responseHandler;
		this._requestId = requestId;
		 new Thread() 
		 { 
				@Override
				public void run() 
				{
					try
					{
						HttpGet httpMethod = new HttpGet(url);
						
						if (headers != null)
							httpMethod.setHeaders(headers);

						
						_client.execute(httpMethod, _httpResponseHandler);
					}
					catch (ClientProtocolException e)
					{

					} catch (IOException e)
					{
					}
				}
		 }.start();
	
	}

	//
	// synchronous version of HTTP Get
	//
	public String executeGetRequest(String url)
	{
		return executeGetRequest(url,null);
	}

	public String executeGetRequest(String url,Header[] headers)
	{
		
		try
		{
			HttpGet httpMethod = new HttpGet(url);
			if (headers != null)
				httpMethod.setHeaders(headers);
			
			HttpResponse response = _client.execute(httpMethod);
			return extractHttpResponse(response);
		}
		catch (ClientProtocolException e)
		{
			Log.i("executeGetRequest:ClientProtocolException", e.getMessage());
	
		} catch (IOException e)
		{
			Log.i("executeGetRequest:IOException", e.getMessage());

		}
		
		return null;
	}
	
	// asynchronous versions of HTTP POST
	public void executePostRequestAsync(final String url,int requestId, HashMap<String, String> parameters,Handler responseHandler)
	{
		executePostRequestAsync(url, requestId, parameters,null,responseHandler,null);
	}

	public void executePostRequestAsync(final String url,int requestId, StringEntity data,Handler responseHandler)
	{
		executePostRequestAsync(url, requestId, null,data,responseHandler,null);
	}

	// -with headers
	// -- without data
	public void executePostRequestAsync(final String url,int requestId, final HashMap<String, String> parameters,Handler responseHandler,final Header[] headers)
	{
		executePostRequestAsync(url, requestId,  parameters,null,responseHandler,headers);		
	}
	
	public void executePostRequestAsync(final String url,int requestId, final StringEntity data,Handler responseHandler,final Header[] headers)
	{
		executePostRequestAsync(url, requestId, null,data,responseHandler,headers);
	}
	// -with headers
	// -- with data
	private void executePostRequestAsync(final String url,int requestId, final HashMap<String, String> parameters,final StringEntity data,Handler responseHandler,final Header[] headers)
	{
		this._callerResponseHandler = responseHandler;
		this._requestId = requestId;
		 new Thread() 
		 { 
				@Override
				public void run() 
				{
					try
					{
						HttpPost httpMethod = createHttpPostMethod(url,parameters,headers,data);
						_client.execute(httpMethod, _httpResponseHandler);
					}
					catch (ClientProtocolException e)
					{

					} catch (IOException e)
					{
					}
				}
		 }.start();
	
	}
	

	// synchronous version of HTTP POST
	public String executePostRequest(String url,HashMap<String, String> parameters)
	{
		return executePostRequest(url,parameters,null,null);
	}

	public String executePostRequest(String url,StringEntity data)
	{
		return executePostRequest(url,null,data,null);
	}

	public String executePostRequest(String url,HashMap<String, String> parameters,Header[] headers)
	{
		return executePostRequest(url,parameters,null,headers);
	}
	
	public String executePostRequest(String url,StringEntity data,Header[] headers)
	{
		return executePostRequest(url,null,data,headers);	
	}
	
	private String executePostRequest(String url,HashMap<String, String> parameters,StringEntity data,Header[] headers)
	{
		try
		{
			/*
			HttpPost httpMethod = new HttpPost(url);
			
			// add the data to the request
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
			
			// loop on the parameters and add them to the POST request
			for (Map.Entry<String, String> entry : parameters.entrySet()) 
			{
				nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}
			httpMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
			
			if (headers != null)
				httpMethod.setHeaders(headers);
			*/
			
			HttpPost httpMethod = createHttpPostMethod(url,parameters,headers,data);
			HttpResponse response = _client.execute(httpMethod);
			return extractHttpResponse(response);
		}
		catch (ClientProtocolException e)
		{
	
		} catch (IOException e)
		{
		}
		
		return null;
	
	}
	
	
	private HttpPost createHttpPostMethod(String url,HashMap<String, String> parameters,Header[] headers,StringEntity data)
	{
		try
		{
			//
			// either parameters or dta is present.not both
			//
			HttpPost httpMethod = new HttpPost(url);

			if (parameters != null)
			{
				// add the data to the request
				List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();

				// loop on the parameters and add them to the POST request
				for (Map.Entry<String, String> entry : parameters.entrySet()) 
				{
					nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
				}

				httpMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
			}

			if (data != null)
			{
				httpMethod.setEntity(data);
			}

			if (headers != null)
				httpMethod.setHeaders(headers);

			return httpMethod;

		}
		catch (Exception e)
		{
			return null;
		}
	}

	private  String convertStreamToString(InputStream is, String encoding) throws IOException {

		if (is != null) 
		{
            StringBuilder sb = new StringBuilder();
            String line;
 
            try 
            {
            	
                BufferedReader reader = new BufferedReader(new InputStreamReader(is, encoding),65535);
                
                while ((line = reader.readLine()) != null) 
                {
                    sb.append(line).append("\n");
                }
                
            }catch(Exception e)
            {
            	Log.i("convertStreamToString", e.getMessage());
            } finally 
            {
                is.close();
            }
            return sb.toString();
        } else {       
            return "";
        }
   }

	private final String extractHttpResponse(HttpResponse response)
	{
			HttpEntity entity = response.getEntity();
			String result = null;
			try
			{
				result = convertStreamToString(entity.getContent(),"UTF8"); 
			} catch (IOException e)
			{
				Log.i(" ",e.getMessage());
			}
			return result;
	}	
	

}
